function Carousel(selector) {
    // {}
    // this -> {}
    // this[[Prototype]] = Carousel.prototype;
    this.carousel = document.querySelector(selector);
    console.log(this.carousel);
    if (!this.carousel) {
        var err = new Error("No element is selected!");
        throw err;
    }

    this.init(); // 自动初始化

    // return this;
}

// 字面量对象
Carousel.prototype = {
    constructor: Carousel,
    init: function () {
        this.getEle();
        this.slideLayout();  // 克隆slide-item中的第一个放到父盒子中 设置布局
        if (this.nav) {
            this.createDot();
            this.dotClick();
        }
        this.autoPlay();
        this.hover();
        if (this.prev && this.next) {
            this.pageSwitch();
        }
    },
    getEle() {
        this.nav = this.carousel.getElementsByClassName("nav")[0];
        // this.liList = this.nav.getElementsByTagName("li");
        this.slideCarousel = this.carousel.getElementsByClassName("slide-carousel")[0];
        this.slideItems = this.slideCarousel.getElementsByClassName("slide-item");
        console.log(this.slideItems);
        this.prev = this.carousel.getElementsByClassName("prev")[0];
        this.next = this.carousel.getElementsByClassName("next")[0];
        this.slideWidth = this.carousel.clientWidth;
        this.timer = null;
        this.index = 0;  // 全局变量记录轮播的下标
    },
    createDot() {
        // 根据放入的图片数量生成对应的点
        var children = this.slideCarousel.getElementsByClassName("slide-item");
        for (var i = 0; i < children.length - 1; i++) {
            var li = document.createElement("li");
            if (i === this.index) {
                li.classList.add("active");
            }
            this.nav.appendChild(li);
        }
        this.liList = this.nav.getElementsByTagName("li");
    },
    slideLayout() {
        // 获取slideCarousel 的 slide-item
        var children = this.slideCarousel.getElementsByClassName("slide-item");
        // 克隆第一个 放到最后的位置
        this.slideCarousel.appendChild(children[0].cloneNode(true));

        // 计算 slideCarousel 的宽度  (n*slideWidth)
        this.slideCarousel.style.width = children.length * this.slideWidth + "px";
        Array.from(this.slideItems).forEach(slideItem => slideItem.style.width = this.slideWidth + "px");
    },
    dotClick: function () {
        var _this = this;
        for (let i = 0; i < this.liList.length; i++) {
            let li = this.liList[i];
            li.onclick = function () {
                console.log(i);

                _this.index = i;

                for (var j = 0; j < _this.liList.length; j++) {
                    _this.liList[j].className = "";
                }
                _this.liList[i].className = "active";

                animate(_this.slideCarousel, "left", -_this.slideWidth * i, "ease-out", function () {
                    console.log("本次运动完毕");
                })
            }
        }
    },
    hover: function () { // this -> obj
        var _this = this;
        this.carousel.onmouseenter = function () {
            clearInterval(_this.timer);
            if (_this.prev && _this.next) {
                _this.prev.style.display = "block";
                _this.next.style.display = "block";
            }

        }
        this.carousel.onmouseleave = function () {
            if (_this.prev && _this.next) {
                _this.prev.style.display = "none";
                _this.next.style.display = "none";
            }
            _this.autoPlay();
        }
    },
    pageSwitch() {
        var _this = this;
        this.prev.onclick = function () {
            _this.index--;
            _this.step();
        }

        this.next.onclick = function () {
            _this.index++;
            _this.step();
        }
    },
    autoPlay() { // this -> obj
        clearInterval(this.timer);
        this.timer = setInterval(() => {
            this.index++; // 0 1 2 3 4
            this.step();
        }, 3000);
    },
    step() {
        // 左键连点 => 左键下标最小值为0(第一张) => 如何让其平滑滚动到第四张 ?
        // 第一张  瞬间切到第五张之后   滚动到  第四张
        if (this.index < 0) { // 如何让第一张平滑滚动到第四张 ?
            this.index = this.slideItems.length - 1;  // 第五张下标
            this.slideCarousel.style.left = - this.slideWidth * this.index + "px";  // 瞬间切到第五张之后 
            this.index--;  // 滚动到  第四张
        }


        // next连续点击 => animate函数重复触发 => 先清除上一个,在启动当前 => 回调函数不会触发
        // => 连续点击 => 临界判断优化处理

        // 解析: next连续点击 => 图片最多只能滚动到第五张(看起来同第一张 -> 临界值) -> 此时再点击应该滚动到第二张 => 如何滚动第二张

        // 超出第五张瞬间切换到第一张   滚动到  第二张

        if (this.index > this.slideItems.length - 1) { // index > 4 => 超出第五张
            this.slideCarousel.style.left = 0;  // 第五张瞬间切换到第一张
            this.index = 0;                 // 第一张对应下标
            this.index++;                   // 滚动到第二张
        }


        if (this.nav) {
            for (var j = 0; j < this.slideItems.length - 1; j++) {
                this.liList[j].className = "";
            }
            var activeIndex = this.index >= this.slideItems.length - 1 ? 0 : this.index;
            this.liList[activeIndex].className = "active";
        }

        animate(this.slideCarousel, "left", -this.slideWidth * this.index, "ease-out", () => {
            // console.log("本次运动完毕");
            // // 回调函数 =>  每次运动完毕 判断是否是第五张对应的下标
            if (this.index >= this.slideItems.length - 1) {
                this.slideCarousel.style.left = 0;
                this.index = 0;
            }
        })
    }
}



/**
    * ele   运动的元素
    * attr  运动的css属性名 left top width height
    * end   运动的终点值
    * fn    回调函数 => 提前决定好要执行的内容, 指定位置调用时执行
    *
    */




function animate(ele, attr, end, type, fn) {   // fn形参 => 接收传入的函数 => 每次运动结束执行
    // debugger;
    var cur = parseFloat(getStyle(ele, attr)); //  1. 记录运动的起始位置   2. 记录每隔10ms之后的位置  1000
    // var end = 1000;  // 终点值
    var speed = 0;

    // 多元素运动
    // 如果有多个元素同时运动 => 期望有对应个数的timer对应每一个运动的元素 => 暂停时清除对应的timer即可  

    // 解决方法
    // 将每个timer存到元素节点的属性上     元素节点 => 是一个对象 => 自定义属性(赋值一个不存在的属性)


    clearInterval(ele.timer);
    ele.timer = setInterval(function () {


        if (type == "linear") {
            // 匀速运动
            speed = end >= cur ? 10 : -10
        } else if (type == "ease-in") {
            // 加速运动   end > cur =>正向运动   end < cur  反向运动 
            speed = end > cur ? speed + 1 : speed - 1;
            // console.log(speed);

        } else if (type == "ease-out") {
            // 缓冲运动    终点值 - 当前值  => 剩余距离  / 缓冲因子  => 每次走剩余n分之1
            //            缓冲因子 => 一般在8-12之间 效果比较好

            speed = (end - cur) / 12;
            speed = speed > 0 ? Math.ceil(speed) : Math.floor(speed);
            // console.log(speed);
        }







        cur += speed;  // 记录每隔10ms之后的位置  
        ele.style[attr] = cur + "px";
        // circle += 60;
        // ele.style.transform = `rotate(${circle}deg)`;

        // cur >= end
        if (Math.abs(cur - end) <= Math.abs(speed)) {  //在跑一次就超了  
            clearInterval(ele.timer);
            ele.style[attr] = end + "px";

            // 每次运动完毕之后执行
            if (fn) {
                fn();
            }
        }

    }, 10);
}

function getStyle(ele, attr) {
    if (window.getComputedStyle) {
        return window.getComputedStyle(ele)[attr];
    } else {
        return ele.currentStyle[attr];
    }
}
